package com.kebabeaters.nakebab.client.presenter;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.google.gwt.view.client.SelectionChangeEvent.HasSelectionChangedHandlers;
import com.google.inject.Inject;
import com.gwtplatform.dispatch.shared.DispatchAsync;
import com.gwtplatform.mvp.client.Presenter;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.NameToken;
import com.gwtplatform.mvp.client.annotations.ProxyCodeSplit;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.PlaceRequest;
import com.gwtplatform.mvp.client.proxy.ProxyPlace;
import com.gwtplatform.mvp.client.proxy.RevealContentEvent;
import com.kebabeaters.nakebab.client.place.NameTokens;
import com.kebabeaters.nakebab.client.place.ParamTokens;
import com.kebabeaters.nakebab.shared.action.tasterranking.GetTasterRankingAction;
import com.kebabeaters.nakebab.shared.action.tasterranking.TasterRankingEntry;
import com.kebabeaters.nakebab.shared.dto.structures.Kebab;
import com.kebabeaters.nakebab.shared.dto.structures.Mark;
import com.kebabeaters.nakebab.shared.dto.structures.Restaurant;

public class KebabRankingPresenter extends
		Presenter<KebabRankingPresenter.MyView, KebabRankingPresenter.MyProxy> {

	public static enum Mode {
		MEAT,
		SAUCE,
		VEGETABLES,
		BREAD,
		PRICE
	}
	
	public static class ListEntry {
		
		private Restaurant restaurant;
		private String name;
		private Double avg;
		private int numberOfMarks;
		private int lp;
		private int plusCount;
		private int minusCount;
		
		public ListEntry(double avg) {
			this.name = "Test1";
			this.avg = avg;
			this.numberOfMarks = 5;
			this.plusCount = 10;
			this.minusCount = 10;
		}
		
		public ListEntry(Restaurant restaurant, Mode mode) {
			this.name = restaurant.getName();
			this.restaurant = restaurant;
			
			avg = 0.0;
			numberOfMarks = 0;
			for (Kebab kebab : restaurant.getKebabs())
				for (Mark mark : kebab.getMarks()) {
					this.plusCount = mark.getPlusCount();
					this.minusCount = mark.getMinusCount();
					
					switch(mode) {
					case MEAT:
						avg += mark.getMeat();
						break;
					case SAUCE:
						avg += mark.getSauce();
						break;
					case VEGETABLES:
						avg += mark.getSauce();
						break;
					case BREAD:
						avg += mark.getBread();
						break;
					case PRICE:
						avg += mark.getPriceForSize();
						break;
					}
					numberOfMarks++;
			}
			
			avg = avg / numberOfMarks;
		}

		public Restaurant getRestaurant() {
			return restaurant;
		}

		public void setRestaurant(Restaurant restaurant) {
			this.restaurant = restaurant;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Double getAvg() {
			return avg;
		}

		public void setAvg(Double avg) {
			this.avg = avg;
		}

		public int getNumberOfMarks() {
			return numberOfMarks;
		}

		public void setNumberOfMarks(int nr) {
			this.numberOfMarks = nr;
		}

		public int getLp() {
			return lp;
		}

		public void setLp(int lp) {
			this.lp = lp;
		}

		public int getPlusCount() {
			return plusCount;
		}

		public void setPlusCount(int plusCount) {
			this.plusCount = plusCount;
		}

		public int getMinusCount() {
			return minusCount;
		}

		public void setMinusCount(int minusCount) {
			this.minusCount = minusCount;
		}	
	}
	
	
	public interface MyView extends View {
		
		void createList(List<ListEntry> resultList);

		HasSelectionChangedHandlers getSelectionChangedHandler();

		Restaurant getSelectedObject();
		
		HasClickHandlers getMeatClickHandler();
		
		HasClickHandlers getVegetablesClickHandler();
		
		HasClickHandlers getSauceClickHandler();
		
		HasClickHandlers getBreadClickHandler();
		
		HasClickHandlers getPriceClickHandler();
	}
	
	private final DispatchAsync dispatcher;
	private final PlaceManager placeManager;
	private Restaurant selectedEntry;
	private List<Restaurant> data;
	private Mode mode;

	@ProxyCodeSplit
	@NameToken(NameTokens.kebabRanking)
	public interface MyProxy extends ProxyPlace<KebabRankingPresenter> {
	}

	@Inject
	public KebabRankingPresenter(final EventBus eventBus, final MyView view,
			final MyProxy proxy, DispatchAsync dispatcher, PlaceManager placeManager) {
		super(eventBus, view, proxy);
		this.dispatcher = dispatcher;
		this.placeManager = placeManager;
	}
	
	@Override
	public void onBind() {
		mode = Mode.PRICE;
		
		getView().getSelectionChangedHandler().addSelectionChangeHandler(
				new Handler() {

					@Override
					public void onSelectionChange(SelectionChangeEvent event) {
						selectedEntry = getView().getSelectedObject();
						
						if (selectedEntry != null) {
							placeManager.revealPlace(new PlaceRequest(
									NameTokens.restaurantDetails).with(ParamTokens.id, selectedEntry.getName()));
						}
						
					}

				});
		
		getView().getMeatClickHandler().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				changeMode(Mode.MEAT);				
			}
		});
		
		getView().getSauceClickHandler().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				changeMode(Mode.SAUCE);				
			}
		});
		
		getView().getVegetablesClickHandler().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				changeMode(Mode.VEGETABLES);				
			}
		});
		
		getView().getBreadClickHandler().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				changeMode(Mode.BREAD);				
			}
		});
		
		getView().getPriceClickHandler().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				changeMode(Mode.PRICE);				
			}
		});
		
	}

	@Override
	protected void revealInParent() {
		RevealContentEvent.fire(this, ContentPresenter.TYPE_Content, this);
	}

	@Override
	protected void onReveal() {
		super.onReveal();
	}
	
	@Override
	public void onReset() {
		super.onReset();
		getEntries();
	}

	private void getEntries() {
		dispatcher.execute(new GetTasterRankingAction(),
				new AsyncCallback<GetTasterRankingAction.Result>() {

					private List<TasterRankingEntry> resultList;

					@Override
					public void onFailure(Throwable caught) {
						caught.printStackTrace();
					}

					@Override
					public void onSuccess(GetTasterRankingAction.Result result) {
						resultList = result.getEntries();

						if (resultList == null) {
							System.out.println("Don't have any data");
						} else {							
							data = new ArrayList<Restaurant>();
							
							for (TasterRankingEntry entry: resultList)
								if (!data.contains(entry.getRestaurant()))
									data.add(entry.getRestaurant());
							
							getView().createList(turnIntoListEntry(data));
						}
					}

				});
	}
	
	private List<ListEntry> turnIntoListEntry(List<Restaurant> list) {
		List<ListEntry> result = new ArrayList<ListEntry>();
		
		for (Restaurant entry : list)
			result.add(new ListEntry(entry, mode));

		
		result = sortList(result);
		
		return result;
	}
	
	private List<ListEntry> sortList(List<ListEntry> list) {
		List<ListEntry> result = new ArrayList<ListEntry>();
		
		ListEntry max = null;
		int size = list.size();
		for (int i = 0; i < size; i++) {
			max = list.get(0);
			for (ListEntry entry : list) {
				if (entry.getAvg() > max.getAvg())
					max = entry;
			}
			max.setLp(i + 1);
			result.add(max);
			list.remove(max);
		}
		
		return result;
	}
	
	private void changeMode(Mode mode) {
		this.mode = mode;
		
		List<ListEntry> list = new ArrayList<ListEntry>();
		
		for (Restaurant entry : data) {
			list.add(new ListEntry(entry, mode));
		}

		getView().createList(sortList(list));
	}
}
